Bug Report B192711
Visible to All Users

CalcDefaultTextSize - Null reference exception - The object is currently in use elsewhere - InvalidOperationException

created 14 years ago

Dear Devexpress team,
we are having a very annoying issue that crash our application in certain circumstances.
The exception and stack trace is the following:

System.NullReferenceException: Riferimento a un oggetto non impostato su un'istanza di oggetto.
   in DevExpress.Utils.AppearanceObject.CalcDefaultTextSize(Graphics g)
   in DevExpress.XtraEditors.ViewInfo.BaseControlViewInfo.CalcTextSizeCore(GraphicsCache cache, String text, Int32 maxWidth)
   in DevExpress.XtraEditors.ViewInfo.BaseControlViewInfo.CalcTextSizeCore(Graphics g, String text, Int32 maxWidth)
   in DevExpress.XtraEditors.ViewInfo.BaseControlViewInfo.CalcTextSize(Graphics g, Boolean useDisplayText)
   in DevExpress.XtraEditors.ViewInfo.BaseEditViewInfo.CalcBestFitTextSize(Graphics g)
   in DevExpress.XtraEditors.ViewInfo.BaseEditViewInfo.CalcBestFit(Graphics g)
   in DevExpress.XtraEditors.ViewInfo.TextEditViewInfo.CalcMinHeightCore(Graphics g)
   in DevExpress.XtraEditors.ViewInfo.BaseEditViewInfo.CalcMinHeight(Graphics g)
   in DevExpress.XtraGrid.Views.Base.ViewInfo.BaseViewInfo.CalcMinEditorHeight(AppearanceObject[] styles)
   in DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.CalcMinRowHeight()
   in DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.CalcRectsConstants()
   in DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.CalcRects(Rectangle bounds, Boolean partital)
   in DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo.Calc(Graphics g, Rectangle bounds)
   in DevExpress.XtraGrid.Views.Base.ColumnView.DoInternalLayout()
   in DevExpress.XtraGrid.Views.Base.ColumnView.CalculateLayout()
   in DevExpress.XtraGrid.Views.Grid.GridView.LayoutChanged()
   in DevExpress.XtraGrid.Views.Base.BaseView.EndUpdateCore(Boolean synchronized)
   in DevExpress.XtraGrid.Views.Base.ColumnView.OnDataController_DataSourceChanged(Object sender, EventArgs e)
   in DevExpress.XtraGrid.Views.Grid.GridView.OnDataController_DataSourceChanged(Object sender, EventArgs e)
   in DevExpress.Data.DataControllerBase.RaiseListSourceChanged()
   in DevExpress.Data.DataControllerBase.OnListSourceChanged()
   in DevExpress.Data.DataControllerBase.SetListSourceCore(IList value)
   in DevExpress.Data.DataControllerBase.OnBindingListChanged(ListChangedEventArgs e)
   in DevExpress.Data.DataController.OnBindingListChanged(ListChangedEventArgs e)

I noticed something very strange:
executing the application inside Visual Studio, it's almost impossible to receive the above exception but as soon as you execute the same application in the same machine (in the same folder) the exception will be raised very soon (almost randomly). We do not have any conditional #IF in our application.

The xtragrid is bound to a bindingsource that has a datatable as datasource. As you suggested in numerous post in this forum, since our loading procedure use multithread technique: we make those steps to fill the data :

  1. clone the datatable that is currently bound to the bindingsource that is bound to the xtragrid.
  2. fill the new cloned datatable of data
  3. change the bindingsource datasource assigning the cloned (and filled of data) datatable (we also dispose the previous datatable before the new assignment)

Since it's now a very long time we are having those kind of issue and since I'm not able to recreate a similar project to reproduce and demonstrate the issue i decided to open up your source code with the purpose of debug it along with our app hoping to find the cause was originating the problem.

I created a new digital key and recompiled all your assembly with this sequence:
Data
Utils
XtraEditors
XtraEditors.Design
XtraRichEdit
XtraTreeList
XtraPivotGrid.Core
Chart.Core
XtraNavbar
XtraBars
XtraLayout
XtraPivotGrid
XtraVerticalGrid
XtraPrinting
XtraGauges.Core
XtraCharts
XtraBars.Design
XtraGrid
XtraLayout.Design
XtraGrid.Design
XtraTreeList.Design
XtraNavbar.Design
XtraPrinting.Design
XtraVerticalGrid.Design
XtraGauges.Win

Running our application along with your (recompiled) dlls i have notices that the routine "CalcDefaultTextSize" (in Devexpress.Utils) in some cases is called and the parameter 'Graphics g' is null; In my first attempt to correct the issue i added the following lines to the beginning of the routine to avoid the use of a null variable and avoid the null reference exception:
if (g == null)
{
return (Size)defSize;
}

-------------------------------
Then i also changed in the same routine the following line from this:

bool pageUnitDisplay = pageUnitDisplay = g.PageUnit == GraphicsUnit.Display;
-------------------------------
to this

bool pageUnitDisplay = true;
try { pageUnitDisplay = g.PageUnit == GraphicsUnit.Display; }
catch { return (Size)defSize; }

and with those two corrections i somehow resolved the error "null reference exception" but after that i had to made other two correction in other 2 routine (PrepareWidthAndKerningArrays AND Calculate) in the same file adding the following statement at the very beginning:

if (graphics == null) { return; }

-------------------------------
Finally i made my last correction in the routine "GetFontCacheByFont" because again it was receiving a null parameter "Graphics graphics" and my application started to work correctly and no exception were raised anymore.

After this i tried to understand why the parameter 'graphincs g' (and similar) was null and analyzing your source code, my conclusion is that the problem is originated in the routine "CalcMinEditorHeight" in Devexpress.XtraGrid)

public virtual int CalcMinEditorHeight(AppearanceObject[] styles) {
int maxH = 0;
Graphics g = GInfo.AddGraphics(null);
try {
Hashtable hash = CalcUniqueEditors();
foreach(DevExpress.XtraEditors.ViewInfo.BaseEditViewInfo view in hash.Values) {
for(int n = 0; n < styles.Length; n++) {
view.PaintAppearance = styles[n];
maxH = Math.Max(view.CalcMinHeight(g) + CellVertIndent * 2, maxH);
}
}
hash.Clear();
}
finally {
GInfo.ReleaseGraphics();
}
return Math.Max(maxH, 17);
}

-------------------------------
Looking at the line "Graphics g = GInfo.AddGraphics(null);" i have noticed that in some cases the function AddGraphics return a Null result and the g variable become null from that moment originating the problem.

Since i don't want to make any changes to your source code and i prefer to use the original version of your software and considering that our application runs fine (with no exception) if executed in Visual Studio and randomly crash if executed outside VS: I'm asking you to help us to understand and correct this issue that is now more then two years we are experiencing just like many user are experiencing similar issue reading your precious forum.

Best regards
Massimo Di Trapani
Alcor Sistemi

Comments (2)
DevExpress Support Team 14 years ago

    Hello Massimo,
    It's possible that the cause of the problem are incorrect multi-threaded operations. Nevertheless, we will check our code for the AddGraphics method. Please bear with us and thank you for your patience.
    Thanks,
    Nick

    DevExpress Support Team 14 years ago

      Hi Alcor,
      Our developers have researched this issue and come to the conclusion that it is impossible to fix this problem without a sample project.
      Most probably, the cause of the problem is that the same object is accessed from different threads, which is prohibited. So, to solve the problem, it is necessary to fix its cause, but not just add a condition to prevent the exception from being thrown. In this case, the exception will appear in another method or, even worse, will not be raised at all, but our controls will behave incorrectly. So, please check your code and make sure that you do not access controls from a background thread. If this does not help you, please try to isolate the problem and send your project to us. We will research your code and try to find the cause.
      Thanks
      Dimitros

      Answers

      created 14 years ago

      Hello Nick and Dimitros,
      I'm glad to tell you that i was able to fix my problem because i came across this post http://www.devexpress.com/Support/Center/p/DB2981.aspx
      In my application, my xtragrid is bounded to a bindingsource that is also bounded to a datatable and the data is loaded with a muthirtread procedure because we don't want a frozen UI while data is fetched to the datatable.
      The problem was fixed mainly thanks to 2 changes:

      1. Data is always loaded in a (new) cloned datatable (instead of clearing data from the current datatable and then load data to the same datatable).
      2. Since the datatable is not the original that was bounded to the bindingsource, i now
            2.1 Raise my event 'BindingDataSourceChanging'
                   2.1.1 my xtragrid parentcontrol handle this event and set the grid.datasource to null
            2.2 Assign the new (cloned) datatable to bindingsource.datasource
            2.3 Raise my event 'BindingDataSourceChanged'
                   2.3.1 my xtragrid parentcontrol handle this event and set the grid.datasource to the previous bindingsource instance again.
        It's pretty hard to explain without a written example but the trick that fixed all my problems are point 1 and 2.
        I hope that my explanation might help all people like me have not slept for several days attempting to resolve this problem
        Thanks again
        Massimo Di Trapani
        AlcorSistemi
        Comments (1)
        DevExpress Support Team 14 years ago

          Hi Massimo ,
          I am glad to hear that you have found a solution to this problem.
          Thank you for sharing it with us. It will be helpful for other programmers who will encounter the same problem.
          Thanks
          Dimitros

          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.